﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Xml;
using TetComp;
using mshtml;
using System.Text.RegularExpressions;
using System.IO;

namespace EyeTracker_IA_Project
{
        
    public partial class FinestraPrincipale : Form
    {

        FileSystemWatcher watcher;
        private List<WordFixXML> ListXML = new List<WordFixXML>();
       
        public FixProcess fp= new FixProcess();
        string subject;
        private System.Windows.Forms.Timer timer;
        private Point webPos, previewPos = new Point(0, 0);
        private List<GazePoint> GazePoints = new List<GazePoint>();
        //public static int cntxWordNumb = 10; //numero parole contesto
        
        //EYE TRACKER
        ITetTrackStatus tetTrackStatus;
        ITetCalibProc tetCalibProc;

        //THREAD
        ListenerEyeTracker let;
        Thread letThread;

        /// <summary>
        /// Costruttore
        /// </summary>
        public FinestraPrincipale()
        {
            InitializeComponent();
            tetTrackStatus = (ITetTrackStatus)new TetTrackStatus();
            tetCalibProc = (ITetCalibProc)new TetCalibProc();
            timer = new System.Windows.Forms.Timer();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = 1000;  //mezzo decimo di secondo
            timer.Enabled = true;
            timer.Stop();
            let = new ListenerEyeTracker();
            letThread = new Thread(let.listener);
            watcher = new FileSystemWatcher();
            watcher.Path = @"D:\xmlricevuti";
            watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName;
            watcher.Filter = "*.xml";
            //watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.Created += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// Monitora se vengono scritti file nella cartella xmlricevuti
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void OnChanged(object source, FileSystemEventArgs e)
        {
            MessageBox.Show("ricevuto");
            richTextBox1.AppendText("caaaa");
        }

        /// <summary>
        /// Funzione che preleva solo le coordinate osservate per piu' di 0.05 secondi 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void timer_Tick(object sender, EventArgs e)
        {
            HtmlDocument htmlDoc = webBrowser.Document;

            if (chkSimulator.Checked) webPos = webBrowser.PointToClient(System.Windows.Forms.Control.MousePosition);
            else
            {
                ValoreObject temp = let.getVal();
                webPos = webBrowser.PointToClient(new Point(temp.getXVal(), temp.getYVal()));
            }

            //controllo se sono sul webbrowser
            if (!(webPos.X < 0 || webPos.Y < 0 || webPos.X > webBrowser.Size.Width || webPos.Y > webBrowser.Size.Height))
            {
                if ( equalsPoint( webPos, previewPos))
                {
                    if (GazePoints.Count == 0 || !(GazePoints.Last().equalsPoint(webPos)))
                    {
                        GazePoints.Add(new GazePoint(webPos.X, webPos.Y + htmlDoc.GetElementsByTagName("HTML")[0].ScrollTop));
                        GazePoints.Last().addTime();
                        Object[] objArray = new Object[2];
                        objArray[0] = (Object)webPos.X;
                        objArray[1] = (Object)webPos.Y;
                        richTextBox1.Text += "\nparola esaminata: " + ((string)webBrowser.Document.InvokeScript("selectWord", objArray)).Trim() + " coodinate:" + webPos.X.ToString() + ":" + webPos.Y + ";\n";
                    }
                    else
                    {
                        GazePoints.Last().addTime();
                    }
                }
                else
                {
                    previewPos = webPos;
                }
            }
        }

        /// <summary>
        /// vede se 2 punti sn nello stesso intorno
        /// </summary>
        /// <param name="p">Point : il punto da confrontare</param>
        /// <returns></returns>
        public bool equalsPoint(System.Drawing.Point p1, System.Drawing.Point p2)
        {
            if (Math.Abs(p1.X- p2.X) < 8 && Math.Abs(p1.Y - p2.Y) < 5)
                return true;
            return false;
        }

        /// <summary>
        /// Avvia l'analisi dei punti osservati e estrae parole e contesto
        /// </summary>
        public void CaptureTerm()
        {
            timer.Stop();
            if( ListXML.Count==0)
                ListXML = fp.Capture(webBrowser, GazePoints, trackBar1.Value,subject);
            else
                ListXML.Concat(fp.Capture(webBrowser, GazePoints, trackBar1.Value, subject));
        }

        private void buttonEndSession_Click(object sender, EventArgs e)
        {
            //scrittura su file XML
            fp.WriteXML(ListXML);
            ListXML.Clear();
        }
           
        /// <summary>
        /// Inietta lo script al termine del caricamento della pagina 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            try
            {
                //questo script conta tutte le parole presenti nel documento
                String jsNum = @"function Conta(){ 
                                    stringa = document.body.createTextRange().text; 
                                    var alpha=/[^A-za-z0-9àèìòùé]/g; 
                                    stringa=stringa.replace(alpha,' '); 
                                    var spazi=/\s+/g; 
                                    stringa = stringa.replace(spazi,' '); 
                                    var reTrim=/\s+$|^\s+/g; 
                                    stringa.replace(reTrim,''); 
                                    var nn= stringa.split(' ').length; 
                                    return nn; 
                                }";
                injectJavaScript(jsNum);
                
                String jsContext = @"function selectContext(X,Y,cntextNum){
		                                var range = document.body.createTextRange(); 
		                                var word='';
                                        var temp='';
		                                var myX = X;
		                                var myY = Y;
		                                var n= (cntextNum/2)+1;
		                                var cont=0;
		                                var pattern = /^[A-za-z0-9àèìòùé()]/; 
		                                range.moveToPoint(myX, myY); 
                                        for (var i=1; i<n; i++){
			                                range.move('word', 1); 
			                                range.expand('word');
			                                temp = range.text;
			                                var b = pattern.test(temp);
			                                if ( b )
			                                {
				                                word = word + '^' + temp;  
			                                }
			                                else{ 
				                                i--;
				                                cont++;
			                                } 
		                                }
		                                range.move('word', 1-cont-n);
		                                for (var i=1; i<n; i++){
			                                range.move('word', -1); 
			                                range.expand('word'); 
			                                temp = range.text;
			                                var b = pattern.test(temp);
			                                if ( b )
			                                {
				                                word = word + '^' + temp;  
			                                }
			                                else{ 
				                                i--;
			                                } 
		                                }
		                                return word;
	                                }";
                injectJavaScript(jsContext);
                
                String jsWord = @"function selectWord(X,Y){ 
		                            var range = document.body.createTextRange(); 
		                            var word;
		                            var myX = X; 
		                            var myY = Y;
		                            range.moveToPoint(myX, myY); 
		                            range.move('word', 0); 
		                            range.expand('word');  
		                            word = range.text; 
		                            return word;
	                            }";	
                injectJavaScript(jsWord);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            timer.Start();
        }

        /// <summary>
        /// Inserisca un javascript passato come stringa
        /// </summary>
        /// <param name="str">la stringa contenente il javascript</param>
        public void injectJavaScript(String str)
        {
            HtmlElement head = webBrowser.Document.GetElementsByTagName("head")[0];
            HtmlElement scriptEl = webBrowser.Document.CreateElement("script");
            IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
            element.type = "text/javascript";
            element.text = str;
            head.AppendChild(scriptEl);
        }

        /// <summary>
        /// Indirizza verso la pagina web richiesta alla pressione del tasto GO
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void GoBtn_Click(object sender, EventArgs e)
        {
            CaptureTerm();
            try
            {
                webBrowser.Url = new System.Uri(@"http:\\" + TxtUrl.Text);
            }
            catch (UriFormatException)
            { }
        }

        /// <summary>
        /// Avvia il catturamento delle parole tramite eye tracker
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackStatusStartButton_Click(object sender, EventArgs e)
        {
            if (subject == String.Empty)
            {
                MessageBox.Show("Before starting the tracker you must login yourself!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                trackBar1.Enabled = false;
                trackStatusStartButton.Enabled = false;
                trackStatusStopButton.Enabled = true;
                buttonlogin.Enabled = false;
                buttonEndSession.Enabled = false;
                if (!chkSimulator.Checked)
                {
                    try
                    {
                        // Si connette all'Eyetracker
                        if (!tetTrackStatus.IsConnected) tetTrackStatus.Connect(serverAddressTextBox.Text, (int)TetConstants.TetConstants_DefaultServerPort);

                        // Lo avvia
                        if (!tetTrackStatus.IsTracking) tetTrackStatus.Start();
                        
                        //Avvia il thread
                        letThread.Start();

                        //Avvia il timer
                        timer.Start();
                    }
                    catch (Exception exc)
                    {
                        MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                //Solo per il mouse
                else timer.Start();
            }
        }

        /// <summary>
        /// Sospende il catturamento delle parole tramite l'eye tracker
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trackStatusStopButton_Click(object sender, EventArgs e)
        {
            trackStatusStartButton.Enabled = true;
            trackStatusStopButton.Enabled = false;
            trackBar1.Enabled = true;
            timer.Stop();
            if (!chkSimulator.Checked)
            {
                try
                {
                    if (tetTrackStatus.IsTracking) tetTrackStatus.Stop();
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                let.requestStop();
            }
            buttonlogin.Enabled = true;
            buttonEndSession.Enabled = true;
            CaptureTerm();
        }

        /// <summary>
        /// Se nella cronologia è presente va nella pagina "Indietro"
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BackBtn_Click(object sender, EventArgs e)
        {
            CaptureTerm();
            if (webBrowser.CanGoBack)
                webBrowser.GoBack();
        }

        /// <summary>
        /// Se nella cronologia è presente va nella pagina "Avanti"
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ForwardBtn_Click(object sender, EventArgs e)
        {
            CaptureTerm();
            if (webBrowser.CanGoForward)
                webBrowser.GoForward();
        }

        /// <summary>
        /// Ricarica, quindi aggiorna la pagina corrente
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void updatePage(object sender, EventArgs e)
        {
            CaptureTerm();
            webBrowser.Refresh();
        }

        /// <summary>
        /// Alla pressione del tasto Home torna alla Home Page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void goToHome(object sender, EventArgs e)
        {
            CaptureTerm();
            webBrowser.GoHome();
        }

        private void search(object sender, EventArgs e)
        {
     
        }

        /// <summary>
        /// Apre una finestra di login
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonLogin(object sender, EventArgs e)
        {
            string value = "";
            if (InputBox.OpenInputBox("Login", "Insert your name and surname, please", ref value) == DialogResult.OK)
            {
                subject = value;
            }
            if (subject != String.Empty)
            {
                trackStatusStartButton.Enabled = true;
            }

        }

        private void calibrateButton_Click(object sender, EventArgs e)
        {
            try
            {
                Calibrate(false);
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void recalibrateButton_Click(object sender, EventArgs e)
        {
            try
            {
                Calibrate(true);
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Fai partire la calibrazione in modalità normale o ricalibrazione.
        /// </summary>
        /// <param name="isRecalibrating">Se usare la ricalibrazione.</param>
        void Calibrate(bool isRecalibrating)
        {
            // Connetti la calibrazione
            if (!tetCalibProc.IsConnected) tetCalibProc.Connect(serverAddressTextBox.Text, (int)TetConstants.TetConstants_DefaultServerPort);

            // Selezione il numero di punti punti da visualizzare
            SetNumberOfCalibrationPoints();

            // Apri la finestra di calibrazione
            tetCalibProc.WindowTopmost = false;
            tetCalibProc.WindowVisible = true;
            tetCalibProc.StartCalibration(isRecalibrating ? TetCalibType.TetCalibType_Recalib : TetCalibType.TetCalibType_Calib, false);
        }

        /// <summary>
        /// Selezione del numero di punti di calibrazione.
        /// </summary>
        void SetNumberOfCalibrationPoints()
        {
            if (ninePtsRadioButton.Checked) tetCalibProc.NumPoints = TetNumCalibPoints.TetNumCalibPoints_9;
            else if (fivePtsRadioButton.Checked) tetCalibProc.NumPoints = TetNumCalibPoints.TetNumCalibPoints_5;
            else if (twoPtsRadioButton.Checked) tetCalibProc.NumPoints = TetNumCalibPoints.TetNumCalibPoints_2;
        }

    }
}
